#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/ioctl.h>

#define NS_PER_SEC 1000000000L
#define CMD_CHRDEV_BUF_SIZE _IOR('S', 1, int)

/* 操作模式枚举 */
enum operation_mode {
    OP_READ,
    OP_WRITE,
    OP_INVALID
};

/* 设备操作结果结构体 */
struct device_operation {
    char *buffer;               // 动态数据缓冲区
    ssize_t data_size;          // 实际读/写字节数
    int buffer_size;            // 设备缓冲区大小
    int err_code;               // 错误码
    char err_msg[256];          // 错误描述
    struct timespec time_used;  // 耗时
};

/* 帮助信息打印 */
static void print_help(const char *prog_name, int buffer_size) {
    printf("Usage:\n");
    printf("Device Buffer Size: %d bytes\n\n", buffer_size);
    printf("Read Operations:\n");
    printf("  %s <device> -r [-i<offset>] [-n<length>] [-v]\n", prog_name);
    printf("Write Operations:\n");
    printf("  %s <device> -w -d <data> [-i<offset>] [-n<max>] [-v]\n", prog_name);
    printf("\nOptions:\n");
    printf("  -r          Read operation\n");
    printf("  -w          Write operation\n");
    printf("  -d <data>   Data to write (max %d bytes)\n", buffer_size);
    printf("  -i<offset>  Operation offset (0-%d)\n", buffer_size-1);
    printf("  -n<length>  Maximum length for operation\n");
    printf("  -v          Show timing and rate statistics\n");
    printf("  --help      Show this help\n");
}

/* 获取设备缓冲区大小 */
static int get_device_buffer_size(int fd) {
    int size = 0;
    if (ioctl(fd, CMD_CHRDEV_BUF_SIZE, &size) < 0) {
        return -errno;
    }
    return size;
}

/* 获取高精度时间 */
static struct timespec get_monotonic_time() {
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return ts;
}

/* 计算时间差 (ns) */
static long time_diff_ns(const struct timespec *start, const struct timespec *end) {
    return (end->tv_sec - start->tv_sec) * NS_PER_SEC + (end->tv_nsec - start->tv_nsec);
}

/* 封装设备操作 */
static struct device_operation device_access(
    int fd,
    enum operation_mode mode,
    int offset,
    int max_length,
    const char *write_data,
    int buffer_size
) {
    struct device_operation result = {0};
    ssize_t bytes_processed = 0;
    struct timespec start_time, end_time;

    /* 初始化缓冲区 */
    result.buffer = malloc(buffer_size);
    if (!result.buffer) {
        result.err_code = ENOMEM;
        snprintf(result.err_msg, sizeof(result.err_msg), "Memory allocation failed");
        return result;
    }

    /* 参数有效性检查 */
    if (offset < 0 || offset >= buffer_size) {
        result.err_code = EINVAL;
        snprintf(result.err_msg, sizeof(result.err_msg), "Invalid offset (0-%d)", buffer_size-1);
        goto cleanup;
    }

    int max_op_len = buffer_size - offset;
    if (max_length > 0 && max_length < max_op_len) {
        max_op_len = max_length;
    }

    /* 记录开始时间 */
    start_time = get_monotonic_time();

    /* 设置操作位置 */
    if (lseek(fd, offset, SEEK_SET) < 0) {
        result.err_code = errno;
        snprintf(result.err_msg, sizeof(result.err_msg), "Seek failed: %s", strerror(errno));
        goto cleanup;
    }

    /* 执行操作 */
    switch (mode) {
        case OP_READ:
            bytes_processed = read(fd, result.buffer, max_op_len);
            break;
        case OP_WRITE: {
            size_t data_len = write_data ? strlen(write_data) : 0;
            if (data_len > max_op_len) {
                data_len = max_op_len;
            }
            memcpy(result.buffer, write_data, data_len);
            bytes_processed = write(fd, result.buffer, data_len);
            break;
        }
        default:
            break;
    }

    /* 检查操作结果 */
    if (bytes_processed < 0) {
        result.err_code = errno;
        snprintf(result.err_msg, sizeof(result.err_msg), "%s failed: %s",
                (mode == OP_READ) ? "Read" : "Write", strerror(errno));
    }
    result.data_size = bytes_processed;

cleanup:
    /* 记录结束时间 */
    end_time = get_monotonic_time();
    result.time_used.tv_sec = end_time.tv_sec - start_time.tv_sec;
    result.time_used.tv_nsec = end_time.tv_nsec - start_time.tv_nsec;
    if (result.time_used.tv_nsec < 0) {
        result.time_used.tv_sec--;
        result.time_used.tv_nsec += NS_PER_SEC;
    }

    return result;
}

/* 打印结果详情 */
static void print_result(const struct device_operation *op, 
                        enum operation_mode mode,
                        int verbose) {
    /* 显示基础信息 */
    printf("[%s Operation]\n", mode == OP_READ ? "Read" : "Write");
    printf("Buffer size: %d bytes\n", op->buffer_size);
    printf("Bytes processed: %zd\n", op->data_size);

    if (mode == OP_READ && op->data_size > 0) {
        printf("Data hex dump:\n");
        for (int i = 0; i < op->data_size; ++i) {
            printf("%02x%c", 
                  op->buffer[i], 
                  ((i+1) % 16 == 0 || i == op->data_size-1) ? '\n' : ' ');
        }
    }

    /* 显示统计信息 */
    if (verbose) {
        long ns = time_diff_ns(&op->time_used, &op->time_used);
        double seconds = (double)ns / NS_PER_SEC;
        printf("\nPerformance:\n");
        printf("Time consumed: %ld.%09ld s\n", 
              op->time_used.tv_sec, op->time_used.tv_nsec);
        if (seconds > 0) {
            printf("Transfer rate: %.2f KB/s\n", 
                  (op->data_size / 1024.0) / seconds);
        }
    }
    printf("\n");
}

int main(int argc, char **argv) {
    int opt;
    char *device = NULL;
    enum operation_mode mode = OP_INVALID;
    int offset = 0;
    int max_length = 0;
    char *write_data = NULL;
    int verbose = 0;
    int fd = -1;
    int buffer_size = 0;

    /* 参数检查 */
    if (argc == 1 || strcmp(argv[1], "--help") == 0) {
        /* 临时打开设备获取缓冲区大小 */
        if (argc > 1 && (fd = open(argv[1], O_RDONLY)) >= 0) {
            buffer_size = get_device_buffer_size(fd);
            close(fd);
        }
        print_help(argv[0], buffer_size > 0 ? buffer_size : 32);
        return EXIT_SUCCESS;
    }

    /* 打开设备获取缓冲区大小 */
    device = argv[optind];
    if ((fd = open(device, O_RDONLY)) < 0) {
        fprintf(stderr, "Failed to open device: %s\n", strerror(errno));
        return EXIT_FAILURE;
    }
    
    if ((buffer_size = get_device_buffer_size(fd)) < 0) {
        fprintf(stderr, "Failed to get buffer size: %s\n", strerror(-buffer_size));
        close(fd);
        return EXIT_FAILURE;
    }
    close(fd);

    /* 重新解析参数 */
    optind = 1;
    while ((opt = getopt(argc, argv, "rwd:i:n:v")) != -1) {
        switch (opt) {
            case 'r': 
                if (mode != OP_INVALID) return EXIT_FAILURE;
                mode = OP_READ;
                break;
            case 'w':
                if (mode != OP_INVALID) return EXIT_FAILURE;
                mode = OP_WRITE;
                break;
            case 'd':
                write_data = optarg;
                break;
            case 'i': 
                offset = atoi(optarg); 
                break;
            case 'n': 
                max_length = atoi(optarg); 
                break;
            case 'v':
                verbose = 1;
                break;
            default: 
                print_help(argv[0], buffer_size); 
                return EXIT_FAILURE;
        }
    }

    /* 参数验证 */
    if (offset >= buffer_size) {
        fprintf(stderr, "Offset exceeds buffer size (%d)\n", buffer_size);
        return EXIT_FAILURE;
    }

    /* 打开设备执行操作 */
    int open_flags = mode == OP_READ ? O_RDONLY : O_WRONLY;
    if ((fd = open(device, open_flags)) < 0) {
        fprintf(stderr, "Failed to open device: %s\n", strerror(errno));
        return EXIT_FAILURE;
    }

    struct device_operation op = device_access(fd, mode, offset, max_length, write_data, buffer_size);
    close(fd);

    op.buffer_size = buffer_size;

    /* 处理结果 */
    if (op.err_code != 0) {
        fprintf(stderr, "OPERATION FAILED: %s\n", op.err_msg);
        free(op.buffer);
        return EXIT_FAILURE;
    }

    print_result(&op, mode, verbose);
    free(op.buffer);

    return EXIT_SUCCESS;
}